﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using myTwitter.BO;
using System.Xml.Linq;
using myBoard.Framework;
using myTwitter.Model;
using System.Windows.Threading;
using System.ComponentModel;
using myTwitter.Sorting;
using System.Collections.ObjectModel;
using myTwitter.BO.Search;
using System.Collections;
using System.Windows.Media;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web;
using myBoard.Framework.Web;

namespace myTwitter.API
{
    public class TwitterProvider : ITwitterProvider
    {
        public string Login { get; set; }
        public string Password { get; set; }
        public event IMessagesUpdateErrorHandler IMessagesUpdateError;
        public event DirectMessagesUpdatedHandler DirectMessagesUpdated;
        public event StatusUpdatedHandler StatusUpdated;
        public event MentionsUpdatedHandler MentionsUpdated;
        public event ConnectedUserInfoUpdatedHandler ConnectedUserInfoUpdated;
        public event VerifyCredentialCompletedHandler VerifyCredentialCompleted;
        public event UserInfoUpdatedHandler UserInfoUpdated;
        public event TrendsUpdatedHandler TrendsUpdated;
        public Exception LastException { get; set; }
        private DispatcherTimer _friendsStatusResfreshTimer;
        private DispatcherTimer _directMessagesResfreshTimer;
        private DispatcherTimer _mentionsResfreshTimer;
        private DispatcherTimer _userInfoResfreshTimer;
        private DispatcherTimer _trendsRefreshTimer;
        private oAuthTwitter _oAuth = new oAuthTwitter();
        private UserOAuthenSettings _currentUserOAuthenSettings;

        public UserOAuthenSettings CurrentUserOAuthenSettings
        {
            get { return _currentUserOAuthenSettings; }
            set { _currentUserOAuthenSettings = value; }
        }

        #region Requests

        private string PerformRequest(oAuthTwitter.Method method, string url, string postData, bool requiresOAuth)
        {
            if (_currentUserOAuthenSettings!=null && string.IsNullOrEmpty(_oAuth.PIN))
            {
                _oAuth.ConsumerKey = _currentUserOAuthenSettings.ConsumerKey;
                _oAuth.ConsumerSecret = _currentUserOAuthenSettings.ConsumerSecret;
                _oAuth.PIN = _currentUserOAuthenSettings.PIN;
                _oAuth.Token = _currentUserOAuthenSettings.Token;
                _oAuth.TokenSecret = _currentUserOAuthenSettings.TokenSecret;
            }
            if(requiresOAuth)
                return _oAuth.oAuthWebRequest(method, url, postData);
            else
                return _oAuth.WebRequest(method, url, postData);
        }

        public void GetAuthorizationCode()
        {
            _oAuth.ConsumerKey = "tClNU5WOQKshp7AJbYAQ";
            _oAuth.ConsumerSecret = "sznrd7y7i8tMqmmxhIwUQRh7TorWOURhqYGPtktQOGM";
            string authLink = _oAuth.AuthorizationLinkGet();
            System.Diagnostics.Process.Start(authLink);
            Connector.HideMyBoard();
        }

        public UserOAuthenSettings Authorize(string code)
        {
            _oAuth.AccessTokenGet(_oAuth.OAuthToken, code.Trim());
            UserOAuthenSettings userOAuthenSettings = new UserOAuthenSettings()
            {
                PIN=_oAuth.PIN,
                Token=_oAuth.Token,
                TokenSecret=_oAuth.TokenSecret,
                Login=Login
            };
            _currentUserOAuthenSettings = userOAuthenSettings;
            return userOAuthenSettings;
        }

        private string Post(string url, string postData, bool requiresOAuth)
        {
            return PerformRequest(oAuthTwitter.Method.POST, url,postData, requiresOAuth);
        }

        private string Get(string url, string postData, bool requiresOAuth)
        {
            return PerformRequest(oAuthTwitter.Method.GET, url, postData, requiresOAuth);
        }

        #endregion

        public void Search(string query)
        {
            BackgroundWorker bw = new BackgroundWorker();
            bw.DoWork += new DoWorkEventHandler(delegate(object sender, DoWorkEventArgs e)
                {
                    List<IMessage> results = new List<IMessage>();
                    string url = string.Format("http://search.twitter.com/search.atom?q={0}",query);
                    string result = Get(url, string.Empty, false);
                    XNamespace nsatom = "http://www.w3.org/2005/Atom";

                    XDocument document = XDocument.Parse(result, LoadOptions.None);
                    IEnumerable<XElement> elements = document.Descendants(nsatom + "entry");
                    foreach (XElement element in elements)
                    {
                        string content = element.Element(nsatom + "content").Value;
                        /*string HTML_TAG_PATTERN = "<.*?>";
                        content = Regex.Replace(content, HTML_TAG_PATTERN, string.Empty);
                        string htmlStrippedContent = content;*/
                        string htmlStrippedContent = HttpUtility.HtmlDecode(content);
                        htmlStrippedContent = HttpUtility.UrlDecode(htmlStrippedContent);

                        results.Add(new Entry()
                        {
                            Id = element.Element(nsatom + "id").Value,
                            LinkUrl = element.Elements(nsatom + "link").First().Attribute("href").Value,
                            Published = DateTime.Parse(element.Element(nsatom + "published").Value).ToUniversalTime(),
                            Updated = DateTime.Parse(element.Element(nsatom + "updated").Value).ToUniversalTime(),
                            Title = element.Element(nsatom + "title").Value,
                            Content = htmlStrippedContent,
                            ImageUrl = element.Elements(nsatom + "link").Last().Attribute("href").Value,
                            //TwitterSource = element.Element(nsatom + "source").Value,
                            //TwitterLanguage = element.Element(nsatom + "lang").Value,
                            Author = new Author()
                            {
                                Name = element.Element(nsatom + "author").Element(nsatom + "name").Value,
                                Uri = element.Element(nsatom + "author").Element(nsatom + "uri").Value
                            }
                        });
                    }
                    e.Result = results;
                });
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(delegate(object sender, RunWorkerCompletedEventArgs e)
                {
                    if (e.Error != null)
                    {
                        if (IMessagesUpdateError != null)
                            IMessagesUpdateError(e.Error);
                    }
                    else
                    {
                        if (SearchCompleted != null)
                            SearchCompleted(e.Result as List<IMessage>);
                    }
                });
            bw.RunWorkerAsync();
        }

        /// <summary>
        /// Ends the session of the authenticating user, returning a null cookie.
        /// Use this method to sign users out of client-facing applications like widgets.
        /// </summary>
        public void EndSession()
        {
            BackgroundWorker bw = new BackgroundWorker();
            bw.DoWork += new DoWorkEventHandler(delegate(object sender, DoWorkEventArgs e)
                {
                    string url = "http://twitter.com/account/end_session.xml";
                    string result = Post(url,string.Empty,true);
                    myTwitter.GlobalController.Settings.IsConnected = false;
                });
            bw.RunWorkerAsync();
        }

        /// <summary>
        /// Updates the authenticating user's status.  Requires the status parameter specified below.
        /// Request must be a POST.
        /// A status update with text identical to the authenticating user's current status will be ignored to prevent duplicates.
        /// </summary>
        /// <param name="status"></param>
        public void UpdateStatus(string status)
        {
            UpdateStatus(status, -1);             
        }

        public void UpdateStatus(string status, long inReplyToStatusId)
        {
            string url = "http://twitter.com/statuses/update.xml";
            string data = string.Empty;

            if (inReplyToStatusId==-1)
                data = string.Format("status={0}", HttpUtility.UrlEncode(status));
            else
                data = string.Format("status={0}&in_reply_to_status_id={1}", HttpUtility.UrlEncode(status), inReplyToStatusId);

            string result = Post(url,data,true);
            RefreshStatus();
        }

        /// <summary>
        /// Updates the authenticating user's status.  Requires the status parameter specified below.
        /// Request must be a POST.
        /// A status update with text identical to the authenticating user's current status will be ignored to prevent duplicates.
        /// </summary>
        /// <param name="status"></param>
        public void UpdateStatusAsync(string status)
        {
            UpdateStatusAsync(status, -1);
        }

        public void UpdateStatusAsync(string status, long inReplyToStatusId)
        {
            BackgroundWorker bw = new BackgroundWorker();
            bw.DoWork += (a, b) =>
            {
                string url = "http://twitter.com/statuses/update.xml";
                string data = string.Empty;

                if (inReplyToStatusId == -1)
                    data = string.Format("status={0}", HttpUtility.UrlEncode(status));
                else
                    data = string.Format("status={0}&in_reply_to_status_id={1}", HttpUtility.UrlEncode(status), inReplyToStatusId);

                string result = Post(url, data, true);
                RefreshStatus();
            };
            bw.RunWorkerCompleted += (a, b) =>
                {
                    if (b.Error != null)
                    {
                        ExceptionsManager.LogException("Sinapse", b.Error, true);
                    }
                };
            bw.RunWorkerAsync();
            
        }

        /// <summary>
        /// Once you call this method, the Twitter provider will not check twitter web site for new Tweets, Direct message or any kind of update.
        /// You shold call this method when you are about to sign out or kill the client.
        /// </summary>
        public void StopAutoRefresh()
        {
            if(_friendsStatusResfreshTimer!=null)
                _friendsStatusResfreshTimer.Stop();
            
            if(_directMessagesResfreshTimer!=null)
                _directMessagesResfreshTimer.Stop();

            if(_mentionsResfreshTimer!=null)
                _mentionsResfreshTimer.Stop();
            
            if(_userInfoResfreshTimer!=null)
                _userInfoResfreshTimer.Stop();

            if (_trendsRefreshTimer != null)
                _trendsRefreshTimer.Stop();
            
            _friendsStatusResfreshTimer = null;
            _directMessagesResfreshTimer = null;
            _mentionsResfreshTimer = null;
            _userInfoResfreshTimer = null;
            _trendsRefreshTimer = null;
        }

        /// <summary>
        /// Sends a new direct message to the specified user from the authenticating user.
        /// Requires both the user and text parameters below.
        /// Request must be a POST.  Returns the sent message in the requested format when successful.  
        /// </summary>
        /// <param name="user">The ID or screen name of the recipient user.</param>
        /// <param name="text">The text of your direct message.  Be sure to URL encode as necessary, and keep it under 140 characters.</param>
        public string SendDirectMessage(string user, string text)
        {
            string url = "http://twitter.com/direct_messages/new.xml";
            string data = string.Format("?user={0}&text={1}", user, HttpUtility.UrlEncode(text));
            return Post(url,data,true);
        }

        /// <summary>
        /// Returns a list of the 20 most recent direct messages sent to the authenticating user. 
        /// </summary>
        /// <returns></returns>
        public List<DirectMessage> GetDirectMessages()
        {
            List<DirectMessage> messages = new List<DirectMessage>();

            string url = "http://twitter.com/direct_messages.xml";
            string result = Get(url,string.Empty,true);
            XDocument document = XDocument.Parse(result, LoadOptions.None);
            var query = from e in document.Root.Descendants("direct_message")
                        select new DirectMessage
                        {
                            Text = HTMLToText(e.Element("text").Value),
                            ID = Convert.ToInt64(e.Element("id").Value),
                            SenderID = Convert.ToInt64(e.Element("sender_id").Value),
                            RecipientID = Convert.ToInt64(e.Element("recipient_id").Value),
                            CreatedAt = (e.Element("created_at").Value.ParseDateTime()),
                            SenderScreenName = e.Element("sender_screen_name").Value,
                            RecipientScreenName = e.Element("recipient_screen_name").Value,
                            Sender = GetUser(e.Element("sender"))
                        };

            foreach (DirectMessage m in query)
                messages.Add(m);

            return messages;
        }

        /// <summary>
        /// Returns a list of the 20 most recent direct messages sent by the authenticating user.  
        /// </summary>
        /// <returns></returns>
        public List<DirectMessage> GetSentDirectMessages()
        {
            List<DirectMessage> messages = new List<DirectMessage>();

            string url = "http://twitter.com/direct_messages/sent.xml";
            string result = Get(url,string.Empty,true);
            XDocument document = XDocument.Parse(result, LoadOptions.None);
            var query = from e in document.Root.Descendants("direct_message")
                        select new DirectMessage
                        {
                            Text = HTMLToText(e.Element("text").Value),
                            ID = Convert.ToInt64(e.Element("id").Value),
                            SenderID = Convert.ToInt64(e.Element("sender_id").Value),
                            RecipientID = Convert.ToInt64(e.Element("recipient_id").Value),
                            CreatedAt = (e.Element("created_at").Value.ParseDateTime()),
                            SenderScreenName = e.Element("sender_screen_name").Value,
                            RecipientScreenName = e.Element("recipient_screen_name").Value
                        };

            foreach (DirectMessage m in query)
                messages.Add(m);

            return messages;
        }

        /// <summary>
        /// Returns the 20 most recent mentions (status containing @username) for the authenticating user.
        /// </summary>
        /// <returns></returns>
        public List<Status> GetMentions()
        {
            List<Status> status = new List<Status>();

            string url = "http://twitter.com/statuses/mentions.xml";
            string result = Get(url,string.Empty,true);
            XDocument document = XDocument.Parse(result, LoadOptions.None);
            var query = from e in document.Root.Descendants("status")
                        select new Status
                        {
                            Text = HTMLToText(e.Element("text").Value),
                            ID = Convert.ToInt64(e.Element("id").Value),
                            Source = e.Element("source").Value,
                            Truncated = Convert.ToBoolean(e.Element("truncated").Value),
                            CreatedAt = (e.Element("created_at").Value.ParseDateTime()),
                            InReplyToUserScreenName = e.Element("in_reply_to_screen_name").Value,
                            IsMention=true,
                            User = GetUser(e.Element("user"))
                        };

            foreach (Status s in query)
                status.Add(s);

            return status;
        }

        /// <summary>
        /// Retrieve specified user tweets
        /// </summary>
        /// <param name="user">User you want to retrieve tweets from</param>
        /// <returns></returns>
        public Tweets GetUserTweets(User user)
        {
            Tweets tweets = new Tweets();

            string url = "http://twitter.com/statuses/user_timeline.xml";
            string data = string.Format("screen_name={0}", user.ScreenName);
            string result = Get(url, data, true);
            XDocument document = XDocument.Parse(result, LoadOptions.None);
            var query = from e in document.Root.Descendants("status")
                        select new Status
                        {
                            Text = HTMLToText(e.Element("text").Value),
                            ID = Convert.ToInt64(e.Element("id").Value),
                            Source = e.Element("source").Value,
                            Truncated = Convert.ToBoolean(e.Element("truncated").Value),
                            CreatedAt = (e.Element("created_at").Value.ParseDateTime()),
                            InReplyToUserScreenName = e.Element("in_reply_to_screen_name").Value,
                            IsMention = true,
                            User = GetUser(e.Element("user"))
                        };

            foreach (Status s in query)
                tweets.Add(s);

            return tweets;
        }

        public Trends GetTrends()
        {
            string url = "http://search.twitter.com/trends.json";
            string result = Get(url, string.Empty,false);
            Trends trends = new Trends(result);
            return trends;
        }

        /// <summary>
        /// Returns the authenticating user's friends, each with current status inline.
        /// They are ordered by the order in which they were added as friends.
        /// It's also possible to request another user's recent friends list via the id parameter below. 
        /// </summary>
        /// <returns></returns>
        public List<Status> GetFriendStatus()
        {
            List<Status> status = new List<Status>();

            string url = "http://twitter.com/statuses/friends_timeline.xml";
            string result = Get(url,string.Empty,true);
            XDocument document = XDocument.Parse(result, LoadOptions.None);
            var query = from e in document.Root.Descendants("status")
                        select new Status
                        {
                            Text = HTMLToText(e.Element("text").Value),
                            ID = Convert.ToInt64(e.Element("id").Value),
                            Source = e.Element("source").Value,
                            Truncated = Convert.ToBoolean(e.Element("truncated").Value),
                            CreatedAt = (e.Element("created_at").Value.ParseDateTime()),
                            InReplyToUserScreenName = e.Element("in_reply_to_screen_name").Value,
                            User = GetUser(e.Element("user"))
                        };

            foreach (Status s in query)
                status.Add(s);

            return status;
        }

        /// <summary>
        /// Returns extended information of a given user, specified by ID or screen name as per the required id parameter below.
        /// This information includes design settings, so third party developers can theme their widgets according to a given user's preferences.
        /// </summary>
        /// <param name="userID">The screen name of a user.</param>
        /// <returns></returns>
        public User GetUser(string userScreenName)
        {
            string url = string.Format("http://twitter.com/users/show/{0}.xml", userScreenName);
            string result = Get(url,string.Empty,true);

            XDocument document = XDocument.Parse(result, LoadOptions.None);

            var query = from e in document.Descendants("user")
                        select GetUser(e);                        

            User user = query.SingleOrDefault();
            if (user != null && userScreenName != Login)
            {
                user.Relationship = GetRelationship(new User() { ScreenName = userScreenName });
            }

            return user;
        }

        private User GetUser(XElement e)
        {
            User user = new User()
            {
                ID = Convert.ToInt64(e.Element("id").Value),
                Name = e.Element("name").Value,
                ScreenName = e.Element("screen_name").Value,
                Location = e.Element("location").Value,
                Description = e.Element("description").Value,
                FollowersCount = Convert.ToInt64(e.Element("followers_count").Value),
                FriendsCount = Convert.ToInt32(e.Element("friends_count").Value),
                ProfileImageUrl = e.Element("profile_image_url").Value,
                StatusesCount = Convert.ToInt64(e.Element("statuses_count").Value),
                TwitterUrl = string.Format("http://twitter.com/{0}",e.Element("screen_name").Value),
                Url = e.Element("url").Value
            };
            if (e.Element("status") != null)
            {
                user.Status = new Status() { Text = HTMLToText(e.Element("status").Element("text").Value) };
            }           
            
            return user;
        }

        public List<User> GetFollowers(string userScreenName, string cursorId)
        {
            List<User> followers = new List<User>();
            string url = string.Format("http://twitter.com/statuses/followers/{0}.xml",userScreenName);
            string result = Get(url, string.Format("?cursor={0}",cursorId), true);

            XDocument document = XDocument.Parse(result, LoadOptions.None);

            var query = from e in document.Root.Descendants("user")
                        select GetUser(e);                        
            
            return query.ToList();
        }

        /// <summary>
        /// Returns a user's friends, each with current status inline. They are ordered by the order in which the user followed them, most recently followed first, 100 at a time.
        /// (Please note that the result set isn't guaranteed to be 100 every time as suspended users will be filtered out.)
        /// Use the cursor option to access older friends. With no user specified, request defaults to the authenticated user's friends.
        /// It's also possible to request another user's friends list via the id, screen_name or user_id parameter.
        /// </summary>
        /// <param name="userScreenName"></param>
        /// <param name="cursorId"></param>
        /// <returns></returns>
        public List<User> GetFriends(string userScreenName, string cursorId)
        {
            List<User> followers = new List<User>();
            string url = string.Format("http://twitter.com/statuses/friends/{0}.xml", userScreenName);
            string result = Get(url, string.Format("?cursor={0}", cursorId), true);

            XDocument document = XDocument.Parse(result, LoadOptions.None);

            var query = from e in document.Root.Descendants("user")
                        select GetUser(e);

            return query.ToList();
        }

        /// <summary>
        /// Returns detailed information about the relationship between the logged in user and an other user.
        /// </summary>
        /// <param name="targetUser">Target user</param>
        /// <returns></returns>
        public Relationship GetRelationship(User targetUser)
        {
            Relationship relationship = new Relationship();
            string url = string.Format("http://twitter.com/friendships/show.xml");
            string result = Get(url, string.Format("target_screen_name={0}", targetUser.ScreenName), true);

            XDocument document = XDocument.Parse(result, LoadOptions.None);

            var query = from e in document.Descendants("relationship")
                        select new Relationship
                        {
                            SourceID = Convert.ToInt64(e.Element("source").Element("id").Value),
                            SourceScreenName = e.Element("source").Element("screen_name").Value,
                            SourceFollowing = Convert.ToBoolean(e.Element("source").Element("following").Value),
                            SourceFollowedBy = Convert.ToBoolean(e.Element("source").Element("followed_by").Value),
                            SourceNotificationsEnabled = Convert.ToBoolean(e.Element("source").Element("notifications_enabled").Value),
                            TargetID = Convert.ToInt64(e.Element("target").Element("id").Value),
                            TargetScreenName = e.Element("target").Element("screen_name").Value,
                            TargetFollowing = Convert.ToBoolean(e.Element("target").Element("following").Value),
                            TargetFollowedBy = Convert.ToBoolean(e.Element("target").Element("followed_by").Value)
                        };
            return query.SingleOrDefault() as Relationship;
        }

        /// <summary>
        /// Allows the authenticating users to follow the user specified in the ID parameter.        
        /// </summary>
        /// <param name="userToFollow">The ID or screen name of the user to befriend. </param>
        public void Follow(User userToFollow)
        {
            string url = string.Format("http://twitter.com/friendships/create/{0}.xml", userToFollow.ScreenName);
            
            // Returns the befriended user in the requested format when successful.
            // Returns a string describing the failure condition when unsuccessful.
            string result = string.Empty;
            try
            {
                result = Post(url,string.Empty,true);
                MBMessageBox msg = new MBMessageBox(string.Format("You are now following {0}", userToFollow.Name),
                        "Follow request completed", "myTwitter", System.Diagnostics.EventLogEntryType.Information, System.Windows.MessageBoxButton.OK);
                msg.ShowDialog();
            }
            catch (Exception ex)
            {
                ExceptionsManager.Write("myTwitter",
                    string.Format(@"Cannot follow {0}. His/Her account may be ""protected"".",userToFollow.Name),
                    string.Format("{0}\r\n{1}",result,ex.ToString())
                    , System.Diagnostics.EventLogEntryType.Warning, true);
            }
        }

        /// <summary>
        /// Allows the authenticating users to unfollow the user specified in the ID parameter.  
        /// </summary>
        /// <param name="userID"></param>
        public void UnFollow(User userToUnFollow)
        {
            string url = string.Format("http://twitter.com/friendships/destroy/{0}.xml", userToUnFollow.ScreenName);

            /// Returns the unfollowed user in the requested format when successful.
            /// Returns a string describing the failure condition when unsuccessful.
            string result = string.Empty;
            try
            {
                result = Post(url,string.Empty,true);
                MBMessageBox msg = new MBMessageBox(string.Format("You don't follow {0} anymore", userToUnFollow.Name),
                        "Unfollow request completed", "myTwitter", System.Diagnostics.EventLogEntryType.Information, System.Windows.MessageBoxButton.OK);
                msg.ShowDialog();
            }
            catch (Exception ex)
            {
                ExceptionsManager.Write("myTwitter", string.Format(@"Cannot stop following {0}.", userToUnFollow.Name),
                    string.Format("{0}\r\n{1}", result, ex.ToString())
                    , System.Diagnostics.EventLogEntryType.Warning, true);
            }
        }        

        /// <summary>
        /// Returns an HTTP 200 OK response code and a representation of the requesting user if authentication was successful;
        /// returns a 401 status code and an error message if not.  Use this method to test if supplied user credentials are valid.
        /// </summary>
        /// <returns></returns>
        public void VerifyCredential()
        {
            BackgroundWorker bw = new BackgroundWorker();
            bw.DoWork += new DoWorkEventHandler(delegate(object sender, DoWorkEventArgs args)
                {
                    string url = "http://twitter.com/account/verify_credentials.xml";
                    string result = string.Empty;
                    try
                    {
                        result = Get(url,string.Empty,true);
                    }
                    catch (Exception ex)
                    {
                        LastException = ex;
                        return;
                    }

                    XDocument document = XDocument.Parse(result, LoadOptions.None);

                    var query = from e in document.Descendants("user")
                                select GetUser(e);

                    User user = query.SingleOrDefault();
                    args.Result = user;
                });

            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(delegate(object sender, RunWorkerCompletedEventArgs e)
                {
                    if (LastException != null)
                    {
                        if (VerifyCredentialCompleted != null)
                            VerifyCredentialCompleted(null);
                    }
                    else
                    {
                        if (VerifyCredentialCompleted != null)
                            VerifyCredentialCompleted(e.Result as User);
                    }
                });

            bw.RunWorkerAsync();            
        }

        public void RefreshStatus()
        {
            _friendsStatusResfreshTimer_Tick(this, null);
        }

        public void RefreshDirectMessages()
        {
            _directMessagesResfreshTimer_Tick(this, null);
        }

        public void RefreshMentions()
        {
            _mentionsResfreshTimer_Tick(this, null);
        }

        public void RefreshConnectedUserInfo()
        {
            _userInfoResfreshTimer_Tick(this, null);
        }

        public void RefreshTrends()
        {
            TrendsRefreshTimer_Tick(this, null);
        }        

        void _friendsStatusResfreshTimer_Tick(object sender, EventArgs e)
        {
            if (!GlobalController.Settings.CanRefresh || !GlobalController.Settings.IsConnected)
                return;

            BackgroundWorker _friendsStatusRefreshBW = new BackgroundWorker();
            _friendsStatusRefreshBW.DoWork += new DoWorkEventHandler(friendsStatusRefreshBW_DoWork);
            _friendsStatusRefreshBW.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_friendsStatusRefreshBW_RunWorkerCompleted);
            _friendsStatusRefreshBW.RunWorkerAsync();
        }


        void _directMessagesResfreshTimer_Tick(object sender, EventArgs e)
        {
            if (!GlobalController.Settings.CanRefresh || !GlobalController.Settings.IsConnected)
                return;

            BackgroundWorker _directMessagesRefreshBW = new BackgroundWorker();
            _directMessagesRefreshBW.DoWork += new DoWorkEventHandler(_directMessagesRefreshBW_DoWork);
            _directMessagesRefreshBW.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_directMessagesRefreshBW_RunWorkerCompleted);
            _directMessagesRefreshBW.RunWorkerAsync();
        }

        void _mentionsResfreshTimer_Tick(object sender, EventArgs e)
        {
            if (!GlobalController.Settings.CanRefresh || !GlobalController.Settings.IsConnected)
                return;

            BackgroundWorker _mentionsRefreshBW = new BackgroundWorker();
            _mentionsRefreshBW.DoWork += new DoWorkEventHandler(_mentionsRefreshBW_DoWork);
            _mentionsRefreshBW.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_mentionsRefreshBW_RunWorkerCompleted);
            _mentionsRefreshBW.RunWorkerAsync();
        }

        void _userInfoResfreshTimer_Tick(object sender, EventArgs e)
        {
            if (!GlobalController.Settings.IsConnected)
                return;

            BackgroundWorker _connectedUserInfoRefreshBW = new BackgroundWorker();
            _connectedUserInfoRefreshBW.DoWork += new DoWorkEventHandler(_connectedUserInfoRefreshBW_DoWork);
            _connectedUserInfoRefreshBW.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_connectedUserInfoRefreshBW_RunWorkerCompleted);
            _connectedUserInfoRefreshBW.RunWorkerAsync();
        }

        void TrendsRefreshTimer_Tick(object sender, EventArgs e)
        {
            if (!GlobalController.Settings.IsConnected)
                return;

            BackgroundWorker trendsRefreshBW = new BackgroundWorker();
            trendsRefreshBW.DoWork += new DoWorkEventHandler(TrendsRefreshBW_DoWork);
            trendsRefreshBW.RunWorkerCompleted += new RunWorkerCompletedEventHandler(TrendsRefreshBW_RunWorkerCompleted);
            trendsRefreshBW.RunWorkerAsync();
        }      

        void _connectedUserInfoRefreshBW_DoWork(object sender, DoWorkEventArgs args)
        {
            User user = GetUser(Login);
            args.Result = user;
        }        

        void _directMessagesRefreshBW_DoWork(object sender, DoWorkEventArgs args)
        {
            List<DirectMessage> receivedDirectMessages = GetDirectMessages();
            args.Result = new List<DirectMessage>(receivedDirectMessages);
        }

        void friendsStatusRefreshBW_DoWork(object obj, DoWorkEventArgs args)
        {
            List<Status> friendsStatus = GetFriendStatus();
            args.Result = new List<Status>(friendsStatus);
        }

        void _mentionsRefreshBW_DoWork(object sender, DoWorkEventArgs args)
        {
            List<Status> mentions = GetMentions();
            args.Result = new List<Status>(mentions);
        }

        void TrendsRefreshBW_DoWork(object sender, DoWorkEventArgs e)
        {
            Trends trends = GetTrends();
            e.Result = trends;
        }

        void _friendsStatusRefreshBW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                if (StatusUpdated != null)
                    StatusUpdated(e.Result as List<Status>);
            }
            else
            {
                if (IMessagesUpdateError != null)
                    IMessagesUpdateError(e.Error);
            }
        }

        void _directMessagesRefreshBW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                if (DirectMessagesUpdated != null)
                    DirectMessagesUpdated(e.Result as List<DirectMessage>);
            }
            else
            {
                if (IMessagesUpdateError != null)
                    IMessagesUpdateError(e.Error);
            }
        }

        void _mentionsRefreshBW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                if (MentionsUpdated != null)
                    MentionsUpdated(e.Result as List<Status>);
            }
            else
            {
                if (IMessagesUpdateError != null)
                    IMessagesUpdateError(e.Error);
            }
        }

        void _connectedUserInfoRefreshBW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                if (ConnectedUserInfoUpdated != null)
                    ConnectedUserInfoUpdated(e.Result as User);
            }
            else
            {
                if (IMessagesUpdateError != null)
                    IMessagesUpdateError(e.Error);
            }
        }

        void TrendsRefreshBW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                if (TrendsUpdated != null)
                    TrendsUpdated(e.Result as Trends);
            }
            else
            {
                if (IMessagesUpdateError != null)
                    IMessagesUpdateError(e.Error);
            }
        } 

        #region ITwitterProvider Members

        public void RefreshStatus(TimeSpan autoRefreshInterval)
        {
            if(_friendsStatusResfreshTimer==null)
                _friendsStatusResfreshTimer = new DispatcherTimer();

            _friendsStatusResfreshTimer.Interval = autoRefreshInterval;
            _friendsStatusResfreshTimer.Tick += new EventHandler(_friendsStatusResfreshTimer_Tick);
            _friendsStatusResfreshTimer.Start();
            _friendsStatusResfreshTimer_Tick(this, null);
        }

        public void RefreshDirectMessages(TimeSpan autoRefreshInterval)
        {
            if(_directMessagesResfreshTimer==null)
                _directMessagesResfreshTimer = new DispatcherTimer();

            _directMessagesResfreshTimer.Interval = autoRefreshInterval;
            _directMessagesResfreshTimer.Tick += new EventHandler(_directMessagesResfreshTimer_Tick);
            _directMessagesResfreshTimer.Start();
            _directMessagesResfreshTimer_Tick(this, null);
        }

        public void RefreshMentions(TimeSpan autoRefreshInterval)
        {
            if(_mentionsResfreshTimer==null)
                _mentionsResfreshTimer = new DispatcherTimer();

            _mentionsResfreshTimer.Interval = autoRefreshInterval;
            _mentionsResfreshTimer.Tick += new EventHandler(_mentionsResfreshTimer_Tick);
            _mentionsResfreshTimer.Start();
            _mentionsResfreshTimer_Tick(this, null);
        }

        public void RefreshUserInfo(TimeSpan autoRefreshInterval)
        {
            if(_userInfoResfreshTimer ==null)
                _userInfoResfreshTimer = new DispatcherTimer();

            _userInfoResfreshTimer.Interval = autoRefreshInterval;
            _userInfoResfreshTimer.Tick += new EventHandler(_userInfoResfreshTimer_Tick);
            _userInfoResfreshTimer.Start();
            _userInfoResfreshTimer_Tick(this, null);
        }

        public void RefreshTrends(TimeSpan autoRefreshInterval)
        {
            if (_trendsRefreshTimer == null)
                _trendsRefreshTimer = new DispatcherTimer();

            _trendsRefreshTimer.Interval = autoRefreshInterval;
            _trendsRefreshTimer.Tick += new EventHandler(TrendsRefreshTimer_Tick);
            _trendsRefreshTimer.Start();
            TrendsRefreshTimer_Tick(this, null);
        }

        

        #endregion

        #region ITwitterProvider Members


        public event SearchCompletedHandler SearchCompleted;

        #endregion

        private string HTMLToText(string html)
        {
            string text = html.Replace("&nbsp;", " ");
            text = text.Replace("&lt;", "<");
            text = text.Replace("&gt;", ">");
            text = text.Replace("&quot;", "\"");
            return text;
        }
    }

    public static class StringExtensions
    {
        public static DateTime ParseDateTime(this string date)
        {
            string dayOfWeek = date.Substring(0, 3).Trim();
            string month = date.Substring(4, 3).Trim();
            string dayInMonth = date.Substring(8, 2).Trim();
            string time = date.Substring(11, 9).Trim();
            string offset = date.Substring(20, 5).Trim();
            string year = date.Substring(25, 5).Trim();
            string dateTime = string.Format("{0}-{1}-{2} {3}", dayInMonth, month, year, time);
            DateTime ret = DateTime.Parse(dateTime);
            return ret;
        }
    }
}
